package com.code.soulnetty.modbus.biz;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.ToString;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.code.soulnetty.modbus.biz.Utils.*;

/**
 * 通道信息
 */
@Getter
@ToString
public class ChannelInfo {
    public static ChannelInfo DEFAULT = new ChannelInfo();
    /**
     * 租户ID
     */
    private String tenantId = "default";
    /**
     * 通道id
     */
    private int channelId;
    /**
     * ip地址
     */
    private String ip;
    /**
     * 端口号
     */
    private int port;
    /**
     * 支持的协议，MODBUS RTU/TCP，BACNET,ODCC等
     */
    private String protocol;

    /**
     * 多个IP时，当前IP信息
     */
    private int curIpInd;

    @JsonIgnore
    private String status = "NORMAL";

    /**
     * 通道任务采集状态 @com.manyun.dchub.odcc.schedule.ChannelStatus
     */
    @JsonIgnore
    private String taskStatus;

    /**
     * 通道关联的设备id列表，直采通道只对应1个设备，转发通道存在多个设备
     */
    @JsonIgnore
    private List<String> deviceGuids;

    /**
     * 设备guid，对于转发通道，此设备guid是采集器设备的guid
     */
    @JsonIgnore
    private String deviceGuid;

    /**
     * 用户名称
     */
    private String user;
    /**
     * 密码
     */
    private String pwd;

    private int channelIndex;
    /**
     * 通道类型
     */
    private String channelType;

    @JsonIgnore
    private String version;

    @JsonIgnore
    private String token;
    /**
     * 最近一次发生异常时间
     */
    @JsonIgnore
    private long errTime;
    /**
     * 最近一次下线时间
     */
    @JsonIgnore
    private long offlineTime;

    /**
     * 上一次采集时间
     */
    @JsonIgnore
    private long lastRunTime;

    private List<String> ipList;
    /**
     * 通道配置信息
     */
    private Map<String, String> config;

    @JsonIgnore
    public String key() {
        StringBuilder sb = new StringBuilder(protocol)
                .append("://")
                .append(ipList.get(curIpInd % ipList.size()))
                .append((port == 80 ? "/" : ":" + port + "/"));
        if (StringUtils.startsWith(protocol, "MODBUS_TCP")) {
            int period = MapUtils.getInteger(config, PERIOD, DEFAULT_PERIOD);
            long timeOut = MapUtils.getLong(config, TIME_OUT, DEFAULT_TIME_OUT);
            long reqIntl = MapUtils.getLong(config, REQ_INTL, DEFAULT_REQ_INTL);
            int retryCount = MapUtils.getInteger(config, RETRY_COUNT_STR, DEFAULT_RETRY_COUNT);
            String taskType = MapUtils.getString(config, TASK_TYPE, DEFAULT_TASK_TYPE);
            sb.append("?period=").append(period).append("&timeOut=").append(timeOut)
                    .append("&reqIntl=").append(reqIntl).append("&retryCount=").append(retryCount)
                    .append("&taskType=").append(taskType);
        }
        if (StringUtils.equals(protocol, Utils.P_BACNET)) {
            int period = MapUtils.getInteger(config, PERIOD, DEFAULT_PERIOD);
            long timeOut = MapUtils.getLong(config, TIME_OUT, DEFAULT_TIME_OUT);
            int sourcePort = MapUtils.getInteger(config, SOURCE_PORT, DEFAULT_SOURCE_PORT);
            int batchSize = MapUtils.getInteger(config, Utils.BACNET_REQ_BATCH_SIZE, Utils.DEFAULT_BACNET_REQ_BATCH_SIZE);
            sb.append("?period=").append(period).append("&timeOut=").append(timeOut)
                    .append("&sourcePort=").append(sourcePort).append("&batchSize=").append(batchSize);
        }
        if (StringUtils.equals(protocol, P_SNMP_V2C)) {
            int period = MapUtils.getInteger(config, PERIOD, DEFAULT_PERIOD);
            long timeOut = MapUtils.getLong(config, TIME_OUT, DEFAULT_TIME_OUT);
            int sourcePort = MapUtils.getInteger(config, SOURCE_PORT, DEFAULT_SOURCE_PORT);
            int snmpReqBatchSize = MapUtils.getInteger(config, Utils.SNMP_REQ_BATCH_SIZE, Utils.DEFAULT_SNMP_REQ_BATCH_SIZE);
            sb.append("?period=").append(period).append("&timeOut=").append(timeOut)
                    .append("&sourcePort=").append(sourcePort).append("&snmpReqBatchSize=").append(snmpReqBatchSize);
        }
        return sb.toString();
    }


    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }

        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        ChannelInfo that = (ChannelInfo) o;

        return channelId == that.getChannelId();
    }

    @Override
    public int hashCode() {
        return channelId;
    }

    public void setTenantId(String tenantId) {
        this.tenantId = tenantId;
    }

    public void setChannelId(int channelId) {
        this.channelId = channelId;
    }

    public void setIp(String ip) {
        this.ip = ip;
        this.ipList = Arrays.stream(StringUtils.split(ip, ",")).collect(Collectors.toList());
    }

    public void setPort(int port) {
        this.port = port;
    }

    public void setProtocol(String protocol) {
        this.protocol = protocol;
    }

    public void setCurIpInd(int curIpInd) {
        this.curIpInd = curIpInd;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public void setTaskStatus(String taskStatus) {
        this.taskStatus = taskStatus;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public void setToken(String token) {
        this.token = token;
    }

    public String curIp() {
        return ipList.get(curIpInd % ipList.size());
    }

    public void setChannelIndex(int channelIndex) {
        this.channelIndex = channelIndex;
    }

    public void setChannelType(String channelType) {
        this.channelType = channelType;
    }

    public void setConfig(Map<String, String> config) {
        this.config = config;
    }

    public void setLastRunTime(long lastRunTime) {
        this.lastRunTime = lastRunTime;
    }

    public void setErrTime(long errTime) {
        this.errTime = errTime;
    }

    public void setOfflineTime(long offlineTime) {
        this.offlineTime = offlineTime;
    }

    public void setDeviceGuids(List<String> deviceGuids) {
        this.deviceGuids = deviceGuids;
    }

    public void setDeviceGuid(String deviceGuid) {
        this.deviceGuid = deviceGuid;
    }
}
